package org.rsbot.script.wrappers;

import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.rsbot.script.methods.Calculations;
import org.rsbot.script.methods.Game;
import org.rsbot.script.methods.MethodContext;
import org.rsbot.script.methods.Players;
import org.rsbot.script.methods.Walking;

public class RSLocalPath extends RSPath
{
  public static final int WALL_NORTH_WEST = 1;
  public static final int WALL_NORTH = 2;
  public static final int WALL_NORTH_EAST = 4;
  public static final int WALL_EAST = 8;
  public static final int WALL_SOUTH_EAST = 16;
  public static final int WALL_SOUTH = 32;
  public static final int WALL_SOUTH_WEST = 64;
  public static final int WALL_WEST = 128;
  public static final int BLOCKED = 256;
  protected RSTile end;
  protected RSTile base;
  protected int[][] flags;
  protected int offX;
  protected int offY;
  private RSTilePath tilePath;

  public RSLocalPath(MethodContext paramMethodContext, RSTile paramRSTile)
  {
    super(paramMethodContext);
    this.end = paramRSTile;
  }

  public boolean traverse(EnumSet<RSPath.TraversalOption> paramEnumSet)
  {
    return (getNext() != null) && (this.tilePath.traverse(paramEnumSet));
  }

  public boolean isValid()
  {
    return (getNext() != null) && (!this.methods.players.getMyPlayer().getLocation().equals(getEnd()));
  }

  public RSTile getNext()
  {
    if (!this.methods.game.getMapBase().equals(this.base)) {
      int[][] arrayOfInt = this.methods.walking.getCollisionFlags(this.methods.game.getPlane());
      if (arrayOfInt != null) {
        this.base = this.methods.game.getMapBase();
        RSTile localRSTile = this.methods.players.getMyPlayer().getLocation();
        RSTile[] arrayOfRSTile = findPath(localRSTile, this.end);
        if (arrayOfRSTile == null) {
          this.base = null;
          return null;
        }
        this.tilePath = this.methods.walking.newTilePath(arrayOfRSTile);
      }
    }
    return this.tilePath.getNext();
  }

  public RSTile getStart()
  {
    return null;
  }

  public RSTile getEnd()
  {
    return this.end;
  }

  public RSTilePath getCurrentTilePath()
  {
    return this.tilePath;
  }

  protected RSTile[] findPath(RSTile paramRSTile1, RSTile paramRSTile2)
  {
    return findPath(paramRSTile1, paramRSTile2, false);
  }

  private RSTile[] findPath(RSTile paramRSTile1, RSTile paramRSTile2, boolean paramBoolean) {
    int i = this.base.getX(); int j = this.base.getY();
    int k = paramRSTile1.getX() - i; int m = paramRSTile1.getY() - j;
    int n = paramRSTile2.getX() - i; int i1 = paramRSTile2.getY() - j;

    int i2 = this.methods.game.getPlane();
    this.flags = this.methods.walking.getCollisionFlags(i2);
    RSTile localRSTile = this.methods.walking.getCollisionOffset(i2);
    this.offX = localRSTile.getX();
    this.offY = localRSTile.getY();

    if ((this.flags == null) || (k < 0) || (m < 0) || (k >= this.flags.length) || (m >= this.flags.length))
      return null;
    if ((n < 0) || (i1 < 0) || (n >= this.flags.length) || (i1 >= this.flags.length)) {
      paramBoolean = true;
      if (n < 0)
        n = 0;
      else if (n >= this.flags.length) {
        n = this.flags.length - 1;
      }
      if (i1 < 0)
        i1 = 0;
      else if (i1 >= this.flags.length) {
        i1 = this.flags.length - 1;
      }

    }

    HashSet localHashSet1 = new HashSet();
    HashSet localHashSet2 = new HashSet();
    Node localNode1 = new Node(k, m);
    Node localNode2 = new Node(n, i1);

    localNode1.f = heuristic(localNode1, localNode2);
    localHashSet1.add(localNode1);

    while (!localHashSet1.isEmpty()) {
      localNode1 = lowest_f(localHashSet1);
      if (localNode1.equals(localNode2))
      {
        return path(localNode1, i, j);
      }
      localHashSet1.remove(localNode1);
      localHashSet2.add(localNode1);
      for (Node localNode3 : successors(localNode1)) {
        if (!localHashSet2.contains(localNode3)) {
          double d = localNode1.g + dist(localNode1, localNode3);
          int i3 = 0;
          if (!localHashSet1.contains(localNode3)) {
            localHashSet1.add(localNode3);
            i3 = 1;
          } else if (d < localNode3.g) {
            i3 = 1;
          }
          if (i3 != 0) {
            localNode3.prev = localNode1;
            localNode3.g = d;
            localNode3.f = (d + heuristic(localNode3, localNode2));
          }
        }
      }

    }

    if ((!paramBoolean) || (this.methods.calc.distanceTo(paramRSTile2) < 10)) {
      return null;
    }
    return findPath(paramRSTile1, pull(paramRSTile2));
  }

  private RSTile pull(RSTile paramRSTile) {
    RSTile localRSTile = this.methods.players.getMyPlayer().getLocation();
    int i = paramRSTile.getX(); int j = paramRSTile.getY();
    if (localRSTile.getX() < i)
      i -= 2;
    else if (localRSTile.getX() > i) {
      i += 2;
    }
    if (localRSTile.getY() < j)
      j -= 2;
    else if (localRSTile.getY() > j) {
      j += 2;
    }
    return new RSTile(i, j);
  }

  private double heuristic(Node paramNode1, Node paramNode2) {
    double d1 = paramNode1.x - paramNode2.x;
    double d2 = paramNode1.y - paramNode2.y;
    if (d1 < 0.0D) d1 = -d1;
    if (d2 < 0.0D) d2 = -d2;
    return d1 < d2 ? d2 : d1;
  }

  private double dist(Node paramNode1, Node paramNode2)
  {
    if ((paramNode1.x != paramNode2.x) && (paramNode1.y != paramNode2.y)) {
      return 1.41421356D;
    }
    return 1.0D;
  }

  private Node lowest_f(Set<Node> paramSet)
  {
    Object localObject = null;
    for (Node localNode : paramSet) {
      if ((localObject == null) || (localNode.f < localObject.f)) {
        localObject = localNode;
      }
    }
    return localObject;
  }

  private RSTile[] path(Node paramNode, int paramInt1, int paramInt2) {
    LinkedList localLinkedList = new LinkedList();
    Node localNode = paramNode;
    while (localNode != null) {
      localLinkedList.addFirst(localNode.toRSTile(paramInt1, paramInt2));
      localNode = localNode.prev;
    }
    return (RSTile[])localLinkedList.toArray(new RSTile[localLinkedList.size()]);
  }

  private List<Node> successors(Node paramNode) {
    LinkedList localLinkedList = new LinkedList();
    int i = paramNode.x; int j = paramNode.y;
    int k = i - this.offX; int m = j - this.offY;
    int n = this.flags[k][m];
    int i1 = this.flags.length - 1;
    if ((m > 0) && ((n & 0x20) == 0) && ((this.flags[k][(m - 1)] & 0x100) == 0)) {
      localLinkedList.add(new Node(i, j - 1));
    }
    if ((k > 0) && ((n & 0x80) == 0) && ((this.flags[(k - 1)][m] & 0x100) == 0)) {
      localLinkedList.add(new Node(i - 1, j));
    }
    if ((m < i1) && ((n & 0x2) == 0) && ((this.flags[k][(m + 1)] & 0x100) == 0)) {
      localLinkedList.add(new Node(i, j + 1));
    }
    if ((k < i1) && ((n & 0x8) == 0) && ((this.flags[(k + 1)][m] & 0x100) == 0)) {
      localLinkedList.add(new Node(i + 1, j));
    }
    if ((k > 0) && (m > 0) && ((n & 0xE0) == 0) && ((this.flags[(k - 1)][(m - 1)] & 0x100) == 0) && ((this.flags[k][(m - 1)] & 0x180) == 0) && ((this.flags[(k - 1)][m] & 0x120) == 0))
    {
      localLinkedList.add(new Node(i - 1, j - 1));
    }
    if ((k > 0) && (m < i1) && ((n & 0x83) == 0) && ((this.flags[(k - 1)][(m + 1)] & 0x100) == 0) && ((this.flags[k][(m + 1)] & 0x180) == 0) && ((this.flags[(k - 1)][m] & 0x102) == 0))
    {
      localLinkedList.add(new Node(i - 1, j + 1));
    }
    if ((k < i1) && (m > 0) && ((n & 0x38) == 0) && ((this.flags[(k + 1)][(m - 1)] & 0x100) == 0) && ((this.flags[k][(m - 1)] & 0x108) == 0) && ((this.flags[(k + 1)][m] & 0x120) == 0))
    {
      localLinkedList.add(new Node(i + 1, j - 1));
    }
    if ((k > 0) && (m < i1) && ((n & 0xE) == 0) && ((this.flags[(k + 1)][(m + 1)] & 0x100) == 0) && ((this.flags[k][(m + 1)] & 0x108) == 0) && ((this.flags[(k + 1)][m] & 0x102) == 0))
    {
      localLinkedList.add(new Node(i + 1, j + 1));
    }
    return localLinkedList;
  }

  protected class Node
  {
    public int x;
    public int y;
    public Node prev;
    public double g;
    public double f;
    public boolean border;

    public Node(int paramInt1, int paramBoolean, boolean arg4)
    {
      boolean bool;
      this.border = bool;
      this.x = paramInt1;
      this.y = paramBoolean;
      this.g = (this.f = 0.0D);
    }

    public Node(int paramInt1, int arg3) {
      this.x = paramInt1;
      int i;
      this.y = i;
      this.g = (this.f = 0.0D);
    }

    public int hashCode()
    {
      return this.x << 4 | this.y;
    }

    public boolean equals(Object paramObject)
    {
      if ((paramObject instanceof Node)) {
        Node localNode = (Node)paramObject;
        return (this.x == localNode.x) && (this.y == localNode.y);
      }
      return false;
    }

    public String toString()
    {
      return "(" + this.x + "," + this.y + ")";
    }

    public RSTile toRSTile(int paramInt1, int paramInt2) {
      return new RSTile(this.x + paramInt1, this.y + paramInt2);
    }
  }
}